//
// Created by 17775 on 2024/10/18.
//

#include "Beam_Stability.h"

void Beam_Stability::stopBeamStability() {
    RayCi_BeamStability_Recording_stop(_iBeamStabilityDocId);

    if (getBeamStabilityDataThreadRunning.load(std::memory_order_acquire)) {
        stopBeamStabilityThread();
//        liveModePowerProfileOptions->close();
    }
}

void Beam_Stability::stopBeamStabilityThread() {
    getBeamStabilityDataThreadRunning.store(false, std::memory_order_release);
    if (m_beamStabilityThread.joinable()) {
        m_beamStabilityThread.join();
    }
}

void Beam_Stability::clearBeamStability() {
    RayCi_BeamStability_Recording_clear(_iBeamStabilityDocId);
}

void Beam_Stability::setFrameSpan(int frames) {
    bool bFrameSpanAvailable = false;
    RayCi_BeamStability_Recording_Settings_isFrameSpanAvailable(_iBeamStabilityDocId, &bFrameSpanAvailable);
    if(bFrameSpanAvailable) {
        RayCi_BeamStability_Recording_Settings_setFrameSpan(_iBeamStabilityDocId, frames);
    }
}

void Beam_Stability::setEveryFrame(bool bEveryFrame) {
    RayCi_BeamStability_Recording_Settings_setEveryFrame(_iBeamStabilityDocId, bEveryFrame);
}

void Beam_Stability::setTimeSpan(double dTime) {
    bool bTimeSpanAvailable = false;
    RayCi_BeamStability_Recording_Settings_isTimeSpanAvailable(_iBeamStabilityDocId, &bTimeSpanAvailable);
    if(bTimeSpanAvailable) {
        if(dTime == 0) {
            setFreeRunning(true);
        } else {
            RayCi_BeamStability_Recording_Settings_setTimeSpan(_iBeamStabilityDocId, dTime);
        }
    }
}

void Beam_Stability::setTimeStep(double dStep) {
    bool bTimeStepAvailable = false;
    RayCi_BeamStability_Recording_Settings_isTimeStepAvailable(_iBeamStabilityDocId, &bTimeStepAvailable);
    if(bTimeStepAvailable) {
        if(dStep == 0) {
            setEveryFrame(true);
        } else {
            RayCi_BeamStability_Recording_Settings_setTimeStep(_iBeamStabilityDocId, dStep);
        }
    }
}

void Beam_Stability::setFreeRunning(bool freeRunning) {
    bool bFreeRunningAvailable = false;
    RayCi_BeamStability_Recording_Settings_isFreeRunningAvailable(_iBeamStabilityDocId, &bFreeRunningAvailable);
    if(bFreeRunningAvailable) {
        RayCi_BeamStability_Recording_Settings_setFreeRunning(_iBeamStabilityDocId, freeRunning);
    }
}

void Beam_Stability::getData() {
    getBeamStabilityDataThreadRunning.store(true, std::memory_order_release);
    m_beamStabilityThread = std::thread(&Beam_Stability::getAllData, this);
}

void Beam_Stability::getAllData() {
    int preLength = 0;
    while (getBeamStabilityDataThreadRunning.load(std::memory_order_acquire)) {
        int dataLength = 0;
        bool bRecording = false;
        RayCi_BeamStability_Recording_isRecording(_iBeamStabilityDocId, &bRecording);
        if(!bRecording) {
            getBeamStabilityDataThreadRunning.store(false, std::memory_order_release);
            emit beamStabilityMeasurementOver();
        }
        RayCi_BeamStability_Chart_Data_getDataLength(_iBeamStabilityDocId, &dataLength);
        if (preLength != dataLength && dataLength > 0) {
            preLength = dataLength;
            BeamStabilityDataBatch batchData;
            batchData.peakRelativeTime.resize(dataLength);
            batchData.peakValue.resize(dataLength);
            batchData.powerRelativeTime.resize(dataLength);
            batchData.powerValue.resize(dataLength);
            batchData.cxRelativeTime.resize(dataLength);
            batchData.cxValue.resize(dataLength);
            batchData.cyRelativeTime.resize(dataLength);
            batchData.cyValue.resize(dataLength);
            batchData.majorRelativeTime.resize(dataLength);
            batchData.majorValue.resize(dataLength);
            batchData.minorRelativeTime.resize(dataLength);
            batchData.minorValue.resize(dataLength);
            batchData.angleRelativeTime.resize(dataLength);
            batchData.angleValue.resize(dataLength);
            RayCi_BeamStability_Chart_Data_getDataAsBinary(_iBeamStabilityDocId, 0, batchData.peakRelativeTime.data(), &dataLength, batchData.peakValue.data(), &dataLength);
            RayCi_BeamStability_Chart_Data_getDataAsBinary(_iBeamStabilityDocId, 1, batchData.powerRelativeTime.data(), &dataLength, batchData.powerValue.data(), &dataLength);
            RayCi_BeamStability_Chart_Data_getDataAsBinary(_iBeamStabilityDocId, 2, batchData.cxRelativeTime.data(), &dataLength, batchData.cxValue.data(), &dataLength);
            RayCi_BeamStability_Chart_Data_getDataAsBinary(_iBeamStabilityDocId, 3, batchData.cyRelativeTime.data(), &dataLength, batchData.cyValue.data(), &dataLength);
            RayCi_BeamStability_Chart_Data_getDataAsBinary(_iBeamStabilityDocId, 4, batchData.majorRelativeTime.data(), &dataLength, batchData.majorValue.data(), &dataLength);
            RayCi_BeamStability_Chart_Data_getDataAsBinary(_iBeamStabilityDocId, 5, batchData.minorRelativeTime.data(), &dataLength, batchData.minorValue.data(), &dataLength);
            RayCi_BeamStability_Chart_Data_getDataAsBinary(_iBeamStabilityDocId, 6, batchData.angleRelativeTime.data(), &dataLength, batchData.angleValue.data(), &dataLength);
            batchData.peakMin = getStatisticalResult(0, 0);
            batchData.peakMax = getStatisticalResult(0, 1);
            batchData.peakAverage = getStatisticalResult(0, 2);
            batchData.peakStd = getStatisticalResult(0, 3);
            batchData.powerMin = getStatisticalResult(1, 0);
            batchData.powerMax = getStatisticalResult(1, 1);
            batchData.powerAverage = getStatisticalResult(1, 2);
            batchData.powerStd = getStatisticalResult(1, 3);
            batchData.centroidXMin = getStatisticalResult(2, 0);
            batchData.centroidXMax = getStatisticalResult(2, 1);
            batchData.centroidXAverage = getStatisticalResult(2, 2);
            batchData.centroidXStd = getStatisticalResult(2, 3);
            batchData.centroidYMin = getStatisticalResult(3, 0);
            batchData.centroidYMax = getStatisticalResult(3, 1);
            batchData.centroidYAverage = getStatisticalResult(3, 2);
            batchData.centroidYStd = getStatisticalResult(3, 3);
            batchData.majorMin = getStatisticalResult(4, 0);
            batchData.majorMax = getStatisticalResult(4, 1);
            batchData.majorAverage = getStatisticalResult(4, 2);
            batchData.majorStd = getStatisticalResult(4, 3);
            batchData.minorMin = getStatisticalResult(5, 0);
            batchData.minorMax = getStatisticalResult(5, 1);
            batchData.minorAverage = getStatisticalResult(5, 2);
            batchData.minorStd = getStatisticalResult(5, 3);
            batchData.angleMin = getStatisticalResult(6, 0);
            batchData.angleMax = getStatisticalResult(6, 1);
            batchData.angleAverage = getStatisticalResult(6, 2);
            batchData.angleStd = getStatisticalResult(6, 3);
            emit getBeamStabilityData(batchData);
        }
        std::this_thread::sleep_for(std::chrono::milliseconds(10));
    }
}

void Beam_Stability::getChartData(int nChartType) {
    bool bValid = false;
    RayCi_BeamStability_Chart_View_isValid(_iBeamStabilityDocId, nChartType, &bValid);
    if(bValid) {
//        RayCi_BeamStability_Recording_start(_iBeamStabilityDocId);
        int dataLength = 0;
        RayCi_BeamStability_Chart_Data_getDataLength(_iBeamStabilityDocId, &dataLength);
        if(dataLength != 0) {
            std::vector<float> vecRelativeTime;
            std::vector<float> vecValue;
            vecRelativeTime.resize(dataLength);
            vecValue.resize(dataLength);
            RayCi_BeamStability_Chart_Data_getDataAsBinary(_iBeamStabilityDocId, nChartType, vecRelativeTime.data(), &dataLength, vecValue.data(), &dataLength);
//            const auto powerData = std::make_shared<PowerProfileData<std::vector<float>>>(vecRelativeTime, vecValue);
//            powerProfileDataReceiveQueueObserver->put(powerData);
            qDebug() << "dataLength = " << dataLength;
        }
    }
}

QString Beam_Stability::getDataUnit(int nChartType) {
    char szUnit[20];
    int size = 20;
    RayCi_BeamStability_Chart_Data_getUnitA(_iBeamStabilityDocId, nChartType, &szUnit[0], &size);
    return QString::fromUtf8(szUnit);
}

double Beam_Stability::getStatisticalResult(int nChartType, int nColumn) {
    double dResult = 0;
    RayCi_BeamStability_Analysis_Statistic_getResult(_iBeamStabilityDocId, nChartType, nColumn, &dResult);
    return dResult;
}

void Beam_Stability::exportReport() {
    RayCi_createDirectoryA("C:\\RayCi\\BeamStability");
    OPENFILENAMEA ofn;
    char szFile[260] = { 0 };
    ZeroMemory(&ofn, sizeof(ofn));
    ofn.lStructSize = sizeof(ofn);
    ofn.hwndOwner = nullptr;
    ofn.lpstrFile = szFile;
    ofn.nMaxFile = sizeof(szFile) / sizeof(szFile[0]) - 1;
    ofn.lpstrFilter = "PDF Files(*.pdf)\0*.pdf*\0All Files(*.*)\0*.*\0\0";
    ofn.nFilterIndex = 1;
    ofn.lpstrInitialDir = "C:\\RayCi\\BeamStability";
    ofn.lpstrTitle = "Save Report As";
    ofn.Flags = OFN_PATHMUSTEXIST | OFN_OVERWRITEPROMPT;
    if (GetSaveFileNameA(&ofn) == TRUE) {
        const char* reportPathName = ofn.lpstrFile;
        std::string reportPathWithExtension = std::string(reportPathName) + ".pdf";
        RayCi_BeamStability_Report_exportA(_iBeamStabilityDocId, reportPathWithExtension.c_str());
        ShellExecuteA(nullptr, "open", reportPathWithExtension.c_str(), nullptr, nullptr, SW_SHOWNORMAL);
    } else {
        MessageBoxA(nullptr, "Export was cancelled.", "Info", MB_OK | MB_ICONINFORMATION);
    }
}

void Beam_Stability::close(bool bWaitWhileClosing) {
    RayCi_BeamStability_close(_iBeamStabilityDocId, bWaitWhileClosing);
}

void Beam_Stability::closeAll(bool bWaitWhileClosing) {
    RayCi_BeamStability_closeAll(bWaitWhileClosing);
}

Beam_Stability::~Beam_Stability() {
    getBeamStabilityDataThreadRunning.store(false, std::memory_order_release);
    if(m_beamStabilityThread.joinable()) {
        m_beamStabilityThread.join();
    }
}